package com.winapi.project.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConstants;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.winapi.project.common.BaseResponse;
import com.winapi.project.common.ResultUtils;
import com.winapi.project.constant.OrderStatus;
import com.winapi.project.model.dto.alipay.AlipayRequest;
import com.winapi.project.model.entity.AlipayInfo;
import com.winapi.project.service.AlipayInfoService;
import com.winapi.project.service.OrderService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.winapi.project.constant.RedisConstant.ALIPAY_TRADE_SUCCESS_RECORD;
import static com.winapi.project.constant.RedisConstant.EXIST_KEY_VALUE;

/**
 * 支付宝沙箱支付
 */
@Slf4j
@RestController
@RequestMapping("/third/alipay")

public class AliPayController {

    private static final String payLog="支付模块-";
//    @Resource
//    private AliPayConfig aliPayConfig;
    @Resource
    private Environment config;
    @Resource
    private AlipayInfoService alipayInfoService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
@Resource
private AlipayClient alipayClient;
@Resource
private OrderService orderService;
//    @Resource
//    private OrderPaySuccessMqUtils orderPaySuccessMqUtils;

      @ApiOperation("统一收单线下交易预创建")
    @PostMapping("/payCode")
    public BaseResponse<String> payCode(@RequestBody AlipayRequest alipayRequest) throws AlipayApiException {
          log.info(payLog+"预创建-进入预创建接口.....");
          //商户订单号
        String outTradeNo = alipayRequest.getTraceNo();
        //订单标题
        String subject = alipayRequest.getSubject();
        //订单总金额
        double totalAmount = alipayRequest.getTotalAmount();

        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        request.setNotifyUrl(config.getProperty("alipay.notify-url"));

        model.setOutTradeNo(outTradeNo);
        model.setTotalAmount(String.valueOf(totalAmount));
        model.setSubject(subject);
        request.setBizModel(model);
        AlipayTradePrecreateResponse response = alipayClient.execute(request);
          log.info(payLog+"预创建-支付宝客户端根据请求参数执行预创建");
          if(response.isSuccess()){
              log.info("调用成功");
          } else {
              log.info("调用失败");
              throw new RuntimeException("预创建交易失败");
          }
        log.info("响应支付二维码详情："+response.getBody());
        String base64 = QrCodeUtil.generateAsBase64(response.getQrCode(), new QrConfig(300, 300), "png");
          log.info(payLog+"预创建-将二维码链接转化为二维码");
          log.info(payLog+"预创建-结束预创建接口.....");
        return ResultUtils.success(base64);
    }

    /**
     * 支付成功回调,注意这里必须是POST接口
     * @param request
     * @return
     * @throws Exception
     */
    @ApiOperation("支付通知")
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/notify")
    public synchronized void payNotify(HttpServletRequest request) throws Exception {
        log.info(payLog+"支付通知-支付通知正在执行......");
       if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
            Map<String, String> params = new HashMap<>();
            Map<String, String[]> requestParams = request.getParameterMap();
            for (String name : requestParams.keySet()) {
                params.put(name, request.getParameter(name));
            }
           log.info(payLog+"支付通知-支付宝开始验签");

            // 支付宝验签
            if (AlipaySignature.rsaCheckV1 (params, config.getProperty("alipay.alipay-public-key"), AlipayConstants.CHARSET_UTF8, AlipayConstants.SIGN_TYPE_RSA2)) {
                //验证成功
                log.info(payLog+"支付通知-支付成功:{}",params);
                // 幂等性保证：判断该订单号是否被处理过，解决因为多次重复收到阿里的回调通知导致的订单重复处理的问题
                Object outTradeNo = stringRedisTemplate.opsForValue().get(ALIPAY_TRADE_SUCCESS_RECORD + params.get("out_trade_no"));
                if (null == outTradeNo ){
                    log.info(payLog+"支付通知-订单号不存在（保证幂等性）");
                    // 验签通过，将订单信息存入数据库
                    AlipayInfo alipayInfo = new AlipayInfo();
                    alipayInfo.setSubject(params.get("subject"));
                    alipayInfo.setTradeStatus(params.get("trade_status"));
                    alipayInfo.setTradeNo(params.get("trade_no"));
                    alipayInfo.setOrderNumber(params.get("out_trade_no"));
                    alipayInfo.setTotalAmount(Double.valueOf(params.get("total_amount")));
                    alipayInfo.setBuyerId(params.get("buyer_id"));
                    alipayInfo.setGmtPayment(DateUtil.parse(params.get("gmt_payment")));
                    alipayInfo.setBuyerPayAmount(Double.valueOf(params.get("buyer_pay_amount")));
                    alipayInfoService.save(alipayInfo);
                    log.info(payLog+"支付通知-创建支付订单并插入数据库支付接口表");
                    //记录处理成功的订单，实现订单幂等性
                    stringRedisTemplate.opsForValue().set(ALIPAY_TRADE_SUCCESS_RECORD +alipayInfo.getOrderNumber(),EXIST_KEY_VALUE,30, TimeUnit.MINUTES);
                    log.info(payLog+"支付通知-将支付订单号保存在Redis中");
                    //修改数据库，完成整个订单功能
                    //更新订单状态
                    orderService.updateStatusByOrderNo(params.get("out_trade_no"), OrderStatus.SUCCESS);
                    log.info(payLog+"支付通知-更新订单状态");

//                    orderPaySuccessMqUtils.sendOrderPaySuccess(params.get("out_trade_no"));
                }
            }
           log.info(payLog+"支付通知-支付宝结束验签");
           log.info(payLog+"支付通知-结束支付通知......");
          }
        }

        @PostMapping("/tradeQuery")
    public BaseResponse<String> tradeQuery(@RequestBody AlipayRequest alipayRequest){
            log.info(payLog+"支付轮询-轮询正在执行......");
            String traceNo = alipayRequest.getTraceNo();
            String s = alipayInfoService.queryOrder(traceNo);
            log.info(payLog+"支付轮询-轮询结束......");
            return ResultUtils.success(s);
        }

    }
